import redis
from redis.exceptions import RedisError, AuthenticationError
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

host = '43.143.226.117'
port = 6379
password = 'p@s5word.'
db = 0
# 使返回值为字符串而非字节
decode_responses=True


class RedisUtil:
    """支持身份验证的Redis连接和操作工具类"""

    def __init__(self, host=host, port=port, db=db, password=None,
                 decode_responses=decode_responses, **kwargs):
        """
        初始化Redis连接

        :param host: Redis服务器主机地址
        :param port: Redis服务器端口
        :param db: 数据库编号
        :param password: Redis认证密码，None表示不需要认证
        :param decode_responses: 是否自动解码响应为字符串
        :param kwargs: 其他Redis连接参数
        """
        self.host = host
        self.port = port
        self.db = db
        self.password = password
        self.decode_responses = decode_responses
        self.kwargs = kwargs
        self.connection = None
        self._connect()

    def _connect(self):
        """建立Redis连接，支持身份验证"""
        try:
            # 创建连接对象
            self.connection = redis.Redis(
                host=self.host,
                port=self.port,
                db=self.db,
                password=self.password,
                decode_responses=self.decode_responses,
                **self.kwargs
            )

            # 测试连接（会自动进行身份验证）
            self.connection.ping()
            logger.info(f"成功连接到Redis: {self.host}:{self.port}, 数据库: {self.db}")
            return True

        except AuthenticationError:
            logger.error("Redis身份验证失败，请检查密码是否正确")
            self.connection = None
            return False
        except RedisError as e:
            logger.error(f"Redis连接失败: {str(e)}")
            self.connection = None
            return False

    def reconnect(self):
        """重新连接Redis"""
        logger.info("尝试重新连接Redis...")
        return self._connect()

    def is_connected(self):
        """检查是否已连接"""
        if not self.connection:
            return False
        try:
            self.connection.ping()
            return True
        except RedisError:
            return False

    def set(self, key, value, expire_seconds=None):
        """
        设置键值对

        :param key: 键
        :param value: 值
        :param expire_seconds: 过期时间(秒)，None表示永不过期
        :return: 操作是否成功
        """
        try:
            if not self.is_connected() and not self.reconnect():
                return False

            result = self.connection.set(key, value)
            if expire_seconds and result:
                self.connection.expire(key, expire_seconds)
            return result
        except RedisError as e:
            logger.error(f"设置键值对失败 {key}: {str(e)}")
            return False

    def hset(self, key, field, value):
        """设置哈希表字段值"""
        try:
            if not self.is_connected() and not self.reconnect():
                return False

            return self.connection.hset(key, field, value)
        except RedisError as e:
            logger.error(f"设置哈希表 {key} 字段 {field} 失败: {str(e)}")
            return False

    def hmset(self, key, mapping, expire_seconds=None):
        """批量设置哈希表字段值"""
        try:
            if not self.is_connected() and not self.reconnect():
                return False

            result = self.connection.hmset(key, mapping)
            if expire_seconds and result:
                self.connection.expire(key, expire_seconds)
            return result
        except RedisError as e:
            logger.error(f"批量设置哈希表 {key} 失败: {str(e)}")
            return False

    def get(self, key):
        """获取键的值"""
        try:
            if not self.is_connected() and not self.reconnect():
                return None

            return self.connection.get(key)
        except RedisError as e:
            logger.error(f"获取键 {key} 的值失败: {str(e)}")
            return None

    def hget(self, key, field):
        """获取哈希表字段的值"""
        try:
            if not self.is_connected() and not self.reconnect():
                return None

            return self.connection.hget(key, field)
        except RedisError as e:
            logger.error(f"获取哈希表 {key} 字段 {field} 的值失败: {str(e)}")
            return None

    def hgetall(self, key):
        """获取哈希表所有字段和值"""
        try:
            if not self.is_connected() and not self.reconnect():
                return None

            return self.connection.hgetall(key)
        except RedisError as e:
            logger.error(f"获取哈希表 {key} 所有字段失败: {str(e)}")
            return None

    def keys(self, pattern='*'):
        """查找符合模式的键"""
        try:
            if not self.is_connected() and not self.reconnect():
                return []

            return self.connection.keys(pattern)
        except RedisError as e:
            logger.error(f"查找符合模式 {pattern} 的键失败: {str(e)}")
            return []

    def delete(self, key):
        """删除键"""
        try:
            if not self.is_connected() and not self.reconnect():
                return 0

            return self.connection.delete(key)
        except RedisError as e:
            logger.error(f"删除键 {key} 失败: {str(e)}")
            return 0

    def expire(self, key, seconds):
        """设置键的过期时间"""
        try:
            if not self.is_connected() and not self.reconnect():
                return False

            return self.connection.expire(key, seconds)
        except RedisError as e:
            logger.error(f"设置键 {key} 的过期时间失败: {str(e)}")
            return False


# 创建带密码的默认Redis工具实例
# 请将your_redis_password替换为实际密码
redis_util = RedisUtil(password=password)

